﻿using System;
using MessageMachine;
using Microsoft.Xna.Framework.Audio;
using System.Collections.Generic;

namespace SoundXMachine
{
    public class SoundControl : ISubscriber
    {
        #region Declarations
        private AudioEngine engine;
        private WaveBank waves;
        private SoundBank sounds;

        /// <summary>What actions to take with received messages.</summary>
        private Dictionary<int, Action<Message>> actions;

        /// <summary>The current sound cues.</summary>
        private List<Cue> cues;
        #endregion //Declarations

        #region Constructors
        /// <summary>
        /// Creates a new sound controller, using files prepared in XACT.
        /// </summary>
        /// <param name="settingsFile">A .xgs file with settings.</param>
        /// <param name="waveBankFile">A .xwb file with wave files.</param>
        /// <param name="soundBankFile">A .xsb file with sound cues.</param>
        public SoundControl(string settingsFile, string waveBankFile, string soundBankFile,
            int playSoundMsg, int stopSoundMsg, int pauseSoundsMsg, int resumeSoundsMsg, int stopAllMsg)
            : this(playSoundMsg, stopSoundMsg, pauseSoundsMsg, resumeSoundsMsg, stopAllMsg)
        {
            engine = new AudioEngine(settingsFile + ".xgs");
            waves = new WaveBank(engine, waveBankFile + ".xwb");
            sounds = new SoundBank(engine, soundBankFile + ".xsb");
            cues = new List<Cue>();
        }

        /// <summary>
        /// Creates a simpler sound controller, using XNA directly without XACT.
        /// </summary>
        /// <param name="playSoundMsg"></param>
        /// <param name="stopSoundMsg"></param>
        /// <param name="pauseSoundsMsg"></param>
        /// <param name="resumeSoundsMsg"></param>
        /// <param name="stopAllMsg"></param>
        public SoundControl(int playSoundMsg, int stopSoundMsg, int pauseSoundsMsg, int resumeSoundsMsg, int stopAllMsg)
        {
            actions = new Dictionary<int, Action<Message>>() {
                {playSoundMsg, m => PlaySound(m.extraInfo.ToString())},
                {stopSoundMsg, m => StopSound(m)},
                {pauseSoundsMsg, m => cues.ForEach(c => c.Pause())},
                {resumeSoundsMsg, m => cues.ForEach(c => c.Resume())},
                {stopAllMsg, m => cues.ForEach(c => c.Stop(AudioStopOptions.Immediate))}
            };
            
            MessagePasser.Subscribe(new int[]{playSoundMsg, stopSoundMsg,
                pauseSoundsMsg, resumeSoundsMsg, stopAllMsg}, this);
        }
        #endregion //Constructors

        public void Update()
        {
            engine.Update();
        }

        #region SoundMethods
        public void PlaySound(string s)
        {
            Cue cue = sounds.GetCue(s);
            if (cue != null)
            {
                cue.Play();
                cues.Add(cue);
            }
        }

        public void PlaySound(List<string> soundNames)
        {
            foreach (string s in soundNames)
                PlaySound(s);
        }

        private void StopSound(Message msg)
        {
            Cue cue = cues.Find(c => c.Name == msg.extraInfo.ToString());
            if (cue != null)
            {
                cue.Stop(AudioStopOptions.Immediate);
                cues.Remove(cue);
            }
        }
        #endregion //SoundMethods

        #region ISubscriber Members
        public void Receive(Message msg)
        {
            actions[msg.msgType](msg);
        }
        #endregion
    }
}